package com.wawu.server.service;

import com.wawu.common.annotation.IOC.Autowired;
import com.wawu.common.annotation.IOC.component.Service;
import com.wawu.common.constant.JwtClaimsConstant;
import com.wawu.common.constant.MessageConstant;
import com.wawu.common.exception.BaseException;
import com.wawu.common.property.JwtProperties;
import com.wawu.common.utils.JwtUtil;
import com.wawu.pojo.dto.AddOrderDTO;
import com.wawu.pojo.dto.AskGoodsMsgDTO;
import com.wawu.pojo.dto.CartDTO;
import com.wawu.pojo.entity.*;
import com.wawu.pojo.query.OrderQuery;
import com.wawu.pojo.vo.GetGoodsCommentVO.CommentVO;
import com.wawu.pojo.vo.GetGoodsCommentVO.GoodCommentVO;
import com.wawu.pojo.vo.GetGoodsCommentVO.UserVO;
import com.wawu.pojo.vo.GoodVO;
import com.wawu.pojo.vo.OrderVO.Goods;
import com.wawu.pojo.vo.OrderVO.OrderVO;
import com.wawu.pojo.vo.getGoodsInfo.getGoodsInfoVO;
import com.wawu.pojo.vo.getGoodsInfo.goodsDetailsVO;
import com.wawu.pojo.vo.getGoodsMsg.getGoodsMsgVO;
import com.wawu.pojo.vo.getGoodsMsg.replyVO;
import com.wawu.pojo.vo.searchGoodVO.goodVO;
import com.wawu.server.dao.*;
import io.jsonwebtoken.Claims;
import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Service
public class MallService {
    @Autowired
    GoodsDAO goodsDAO;
    @Autowired
    GoodsDetailsDAO goodsDetailsDAO;
    @Autowired
    OrdersDAO ordersDAO;
    @Autowired
    MessagesDAO messagesDAO;
    @Autowired
    ReplyDAO relayDAO;
    @Autowired
    UsersDAO usersDAO;
    @Autowired
    CommentDAO commentDAO;

    /**
     * 通过商品类型获取商品列表
     * @param typeId:(-1时表示查全部)
     * @return
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public List<GoodVO> getGoodVOsByTypeId(Long typeId) throws SQLException, InvocationTargetException, IllegalAccessException {
//        List<Good> goods = goodsDAO.getGoodsByType(typeId==-1?null:typeId);
        List<Good> goods=goodsDAO.getGoods(Good.builder()
                .typeId(typeId==-1?null:typeId)//设置为空表示查全部
                .build());
        List<GoodVO> goodVOList=new ArrayList<>();
        for(Good good:goods){
            GoodVO goodVO=new GoodVO();
            BeanUtils.copyProperties(goodVO,good);
            //获取商品单价
            float priceByGoodsId = goodsDetailsDAO.getPriceByGoodsId(good.getId());
            goodVO.setPrice(priceByGoodsId);

            goodVOList.add(goodVO);
        }
        return goodVOList;
    }
    /**
     * 通过商品状态获取订单（隐含了用户信息）
     * @param state
     * @param token
     * @return
     */
    public List<OrderVO> getOrderByState(Integer state, String token) throws SQLException {
        //通过token用户id
            //DONE 待解决：UserId怎么会是Long
            //发现是这个依赖本身的问题，转换为Long就行
        Claims claims = JwtUtil.parseJWT(JwtProperties.secretKey, token);
        Long userId = Long.parseLong(claims.get(JwtClaimsConstant.USER_ID).toString());
        //条件查询订单
        OrderQuery orderQuery=OrderQuery.builder()
                .state(state==-1?null:state)//等于-1默认查全部
                .userId((userId.longValue())).build();
        //查询具体的订单详情
        List<OrderVO> orderVOS=new ArrayList<>();
        for (Order order : ordersDAO.getOrders(orderQuery)) {
            //查询订单的商品详情
            GoodDetail goodDetail = goodsDetailsDAO.getGoodDetails(GoodDetail.builder()
                    .id(order.getGoodsDetailId()).build()).get(0);//主键查询默认只有一个
            //查询订单的商品信息（根据商品详情中的商品id（多对一））
            Good good = goodsDAO.getGoods(Good.builder()
                    .id(goodDetail.getGoodsId()).build()).get(0);//主键查询默认只有第一个

            //DONE 待完成本处只有已完成的订单需要返回评论（后续再细看业务规则）
            //如果是已完成订单，那就看看评价过没有
            boolean hasComment=false;
            if(order.getState()==Order.STATE_COMPLETED){
                if(commentDAO.hasComment(order.getId())){
                    hasComment=true;
                }
            }
            //整合成返回结果
                //这里有一些业务规则不好使用属性复制，所以这里直接暴力复制
            Goods goods=Goods.builder()
                    .img(good.getImg())
                    .id(good.getId().toString())
                    .name(good.getName())
                    .goodsDetailId(goodDetail.getId().toString())
                    .spec(goodDetail.getSpecName())//订单肯定时选了商品对应的规格
                    .unitPrice(goodDetail.getUnitPrice())
                    .build();
            OrderVO orderVO= OrderVO.builder()
                    .id(order.getId().toString())
                    .createtime(order.getCreateTime().toString())//TODO 待完成：注意下日期
                    .goods(goods)
                    .goodsNum(order.getGoodsNum())
                    .amount(order.getAmount())
                    .state(order.getState())
                    .hasComment(hasComment)
                    .build();
            orderVOS.add(orderVO);
        }
        return orderVOS;
    }


    /**
     * 购物
     * @param addOrderDTO
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public void addOrder(AddOrderDTO addOrderDTO) throws SQLException, InvocationTargetException, IllegalAccessException {
        Claims claims = JwtUtil.parseJWT(JwtProperties.secretKey, addOrderDTO.getToken());
        Long UserId = Long.parseLong(claims.get(JwtClaimsConstant.USER_ID).toString());
        ordersDAO.insert(Order.builder()
                .userId(UserId)
                .goodsDetailId(Long.valueOf((addOrderDTO.getGoodsDetailId())))
                .goodsNum(Math.toIntExact((addOrderDTO.getNum())))
                .amount(addOrderDTO.getAmount())
                .state(addOrderDTO.getState())
                .updateTime(LocalDateTime.now())
                .createTime(LocalDateTime.now())
                .build());
        if (addOrderDTO.getState() == Order.STATE_PENDING_SHIPMENT) {
            List<GoodDetail> goodDetails = goodsDetailsDAO.getGoodDetails(GoodDetail.builder()
                    .id(Long.valueOf(addOrderDTO.getGoodsDetailId()))
                    .build());
            if(goodDetails==null||goodDetails.isEmpty()){
                throw new BaseException(MessageConstant.GOOD_DETAIL_NOT_EXIST+":"+addOrderDTO.getGoodsDetailId());
            }
            int stockNum = 0;
            for (GoodDetail goodDetail : goodDetails) {
                stockNum = goodDetail.getStockNum();
            }
            int newNum = (int) (stockNum - addOrderDTO.getNum());
            goodsDetailsDAO.update(GoodDetail.builder()
                    .id(Long.valueOf(addOrderDTO.getGoodsDetailId()))
                    .stockNum(newNum)
                    .build());
        }
    }

    //TODO 待完成：如何设置为事务
    //DONE 待完成：后续改成不重复购买同一个订单的，现在是为了方便调试
    /**
     * 购物车结算
     * （这里不改成cart，而是通过order订单中的信息）
     * 注意：设置成事务
     * @param cartList
     */
    public void settleAccounts(List<CartDTO> cartList) throws SQLException {
        System.out.println(cartList);
        for (CartDTO cart:cartList){
            //1. 首先先查询订单
            List<Order> orders = ordersDAO.getOrders(OrderQuery.builder()
                    .id(Long.parseLong(cart.getId()))
                    .build());//主键查询默认就是1个
            //没有查到这个订单
            if(orders==null||orders.isEmpty()){
                throw new BaseException(MessageConstant.ORDER_NOT_EXIST +":"+cart.getId());
            }
            Order order=orders.get(0);
                //订单不能够重复购买（调试时，可以注释掉）
            if(Order.STATE_PENDING_SHIPMENT==order.getState()){
                throw new BaseException(MessageConstant.ORDER_COUNT_NOT_REPEAT_PURCHASE+":"+cart.getId());
            }
            //2. 查询商品详情找到对应规格的库存
            GoodDetail goodDetail = goodsDetailsDAO.getGoodDetails(GoodDetail.builder()
                    .id(order.getGoodsDetailId())
                    .build()).get(0);//也是主键查询
            //3. 如果库存足够，更新库存；否则返回异常
            Integer newStockNum=goodDetail.getStockNum()-order.getGoodsNum();
                //库存不足
            if(newStockNum<=0){
                throw new BaseException(MessageConstant.GOODS_DETAILS_STOCKNUM_LACK);
            }
                //更新库存
            goodsDetailsDAO.update(GoodDetail.builder()
                    .id(goodDetail.getId())//注意下这里，一定是要用id
                    .stockNum(newStockNum).build());

            //4. 更新订单状态为待发货，同时更新订单中的购买数量和总金额
            ordersDAO.update(Order.builder()
                    .id(order.getId()) // 使用订单主键更新
                    .state(Order.STATE_PENDING_SHIPMENT) // 设置状态为待发货
                    .goodsNum(order.getGoodsNum()) // 更新购买数量
                    .amount(order.getAmount()) // 更新总金额
                    .build());
        }
    }



    /**
     * 获取商品详细信息
     * @param id
     * @return
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public getGoodsInfoVO getGoodsInfo(Long id) throws SQLException, InvocationTargetException, IllegalAccessException {
        List<Good> goods = goodsDAO.getGoods(Good.builder()
                .id(id)
                .build());//id查询默认是一个
        if(goods==null||goods.isEmpty()){
            throw new BaseException(MessageConstant.GOOD_NOT_EXIST+":"+id);
        }
        Good good=goods.get(0);
        getGoodsInfoVO getGoodsInfoVO = new getGoodsInfoVO();
        BeanUtils.copyProperties(getGoodsInfoVO,good);
        //获取商品规格描述
        List<GoodDetail> goodDetailByGoodId = goodsDetailsDAO.getGoodDetails(GoodDetail.builder()
                .goodsId(good.getId())
                .build());
        getGoodsInfoVO.setSpecs(new ArrayList<>());
        for(GoodDetail goodDetail:goodDetailByGoodId){
            goodsDetailsVO goodsDetailsVO = new goodsDetailsVO();
            BeanUtils.copyProperties(goodsDetailsVO,goodDetail);
            getGoodsInfoVO.getSpecs().add(goodsDetailsVO);
        }
        return getGoodsInfoVO;
    }

    /**
     * 搜索商品
     * @param keyword
     * @return
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public List<goodVO> searchGoodVOByKeyword(String keyword) throws SQLException, InvocationTargetException, IllegalAccessException {
        List<Good> goods = goodsDAO.getGoods(Good.builder()
                .name(keyword)
                .build());
        List<goodVO> goodVOList=new ArrayList<>();
        for(Good good:goods){
            goodVO goodVO=new goodVO();
            BeanUtils.copyProperties(goodVO,good);
            //获取商品单价
            float priceByGoodsId = goodsDetailsDAO.getPriceByGoodsId(good.getId());
            goodVO.setPrice(priceByGoodsId);
            goodVOList.add(goodVO);
        }
        return goodVOList;
    }


    /**
     * 获取商品问答信息
     * @param goodsId
     * @return
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public List<getGoodsMsgVO> getGoodsMsgByGoodsId(Long goodsId) throws SQLException, InvocationTargetException, IllegalAccessException {
        List<Message> messages = messagesDAO.getByGoodsId(goodsId);
        List<getGoodsMsgVO> messageVOList=new ArrayList<>();
        for(Message message:messages){
            getGoodsMsgVO getGoodsMsgVO = new getGoodsMsgVO();
            BeanUtils.copyProperties(getGoodsMsgVO,message);
            getGoodsMsgVO.setTime(message.getCreatetime());
            //获取昵称
            String nickNameById = usersDAO.getNickNameById(message.getUserId());
            getGoodsMsgVO.setAsker(nickNameById);
            //获取回复
            Reply relayById = relayDAO.getRelayById(message.getId());
            replyVO replyVO = new replyVO();
            if(relayById!=null){
                BeanUtils.copyProperties(replyVO,relayById);
                replyVO.setTime(message.getCreatetime());
            }
            getGoodsMsgVO.setReply(replyVO);
            messageVOList.add(getGoodsMsgVO);
        }
        return messageVOList;
    }
    /**
     * 通过商品id获取评论(已修改)
     * @param goodsId
     * @return
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public GoodCommentVO getGoodsCommentByGoodsId(Long goodsId) throws SQLException, InvocationTargetException, IllegalAccessException {
        GoodCommentVO goodCommentVO=new GoodCommentVO();
        goodCommentVO.setCommentList(new ArrayList<>());
        int sum=0;//计算总和

        List<Comment> commentsByGoodsId = commentDAO.getCommentsByGoodsId(goodsId);
        for(Comment comment:commentsByGoodsId){
            //1. 获取评论表相关信息
            CommentVO commentVO=new CommentVO();
            BeanUtils.copyProperties(commentVO,comment);//这里可以不复制了，不相关的有点多
                //有几个返回的名字有点不同
            commentVO.setTime(comment.getCreateTime());
            commentVO.setComment(comment.getContent());

            sum+=comment.getScore();
            //2. 获取user详细信息，并设置
            User userById = usersDAO.getUserById(comment.getUserId());
            UserVO userVO=new UserVO();
            BeanUtils.copyProperties(userVO,userById);
            commentVO.setUser(userVO);
                //TODO 待完成：注销用户的判断，以及其对应的头像
            //3. 获取规格说明，并设置
            String specNameByGoodsId = goodsDetailsDAO.getSpecNameById(comment.getGoodsDetailId());//注意了不是comment.getId()
            commentVO.setSpecName(specNameByGoodsId);

            goodCommentVO.getCommentList().add(commentVO);
        }
        goodCommentVO.setRate((double) sum /commentsByGoodsId.size());
        return goodCommentVO;
    }

    /**
     * 商品问答
     * @param askGoodsMsgDTO
     * @throws SQLException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public void askGoodsMsg(AskGoodsMsgDTO askGoodsMsgDTO) throws SQLException, InvocationTargetException, IllegalAccessException {
        String token = askGoodsMsgDTO.getToken();
        Claims claims = JwtUtil.parseJWT(JwtProperties.secretKey, token);
        Long userId = Long.parseLong(claims.get(JwtClaimsConstant.USER_ID).toString());
        messagesDAO.insert(Message.builder()
                .goodsId(Long.parseLong(askGoodsMsgDTO.getGoodsId()))
                .userId(userId)
                .content(askGoodsMsgDTO.getMsg())
                .createtime(LocalDateTime.now())
                .build()
        );
    }
    //TODO 待完成：本处应该设置为事务
    /**
     * 根据订单id删除订单
     * @param orderId
     * @return
     */
    public void deleteOrderById(Long orderId) throws SQLException {
        //1. 先通过订单id查询订单
        List<Order> orders = ordersDAO.getOrders(OrderQuery.builder()
                .id(orderId).build());//主键查询，默认就是一个
        //前面写的代码可能有点问题，就是没有判断为空的情况
        if(orders==null||orders.isEmpty()){
            throw new BaseException(MessageConstant.ORDER_NOT_EXIST);
        }
        Order order=orders.get(0);//默认就是一个
        //2. 订单为待付款时，感觉才要删
        //          TODO 本处先跳过，现在没必要陷入业务逻辑中
        //              本处代码逻辑跟原型系统不同
        //              除了已完成订单和未付款订单外，其它状态的订单被删除，库存量都要加回去

        //3. 删除订单
        ordersDAO.deleteById(orderId);
    }
}
